package com.yyfax.infrastructure.mvp;

import android.util.SparseArray;
import com.yyfax.common.CLog;
import com.yyfax.infrastructure.eventbus.EventAgent;
import com.yyfax.infrastructure.network.entity.BaseResultEntity;
import com.yyfax.infrastructure.network.exception.RetryException;

import rx.Observable;
import rx.Subscriber;
import rx.Subscription;
import rx.functions.Func1;
import rx.schedulers.Schedulers;

/**
 * Created by HenryZhang on 2017/2/22.
 * Copyright © 2017 www.yylending.com. All Rights Reserved.
 */
@SuppressWarnings("unchecked")
public abstract class Model<T> implements IModel<T> {//}, Func1<BaseResultEntity<T>, BaseResultEntity> {
	private SparseArray<Subscription> mExecuteMap = new SparseArray<>();

	/**
	 * 检查该请求是否重复
	 */
	public boolean hadSameExecute(int functionalCode) {
		Subscription subscription = mExecuteMap.get(functionalCode);
		return subscription != null;
	}

	/**
	 * 存储本次请求记录，需要与{@link #completed(int functionalCode)}配套使用
	 */
	public void executing(int functionCode, Subscription subscription) {
		mExecuteMap.put(functionCode, subscription);
	}

	/**
	 * 清除本次请求记录，需要与{@link #executing(int functionalCode, Subscription subscription)}配套使用
	 */
	public void completed(int functionCode) {
		mExecuteMap.remove(functionCode);
	}

	/**
	 * 取消请求（实际上是不接收该请求的回调，即调用取消订阅方法{@link Subscription#unsubscribe()}），网络层的Request发送之后是无法撤回滴
	 */
	public void cancel(int functionalCode) {
		Subscription subscription = mExecuteMap.get(functionalCode);
		if (subscription != null) {
			subscription.unsubscribe();
			mExecuteMap.remove(functionalCode);
		}
	}

	public Observable execute(Object params, int functionalCode, final Object extraParam, final String requestPage) {
		Observable prepareObservable = prepareExecute(getObservable(params, functionalCode));//可以检查是否重复
		return resultFilter(prepareObservable, functionalCode, extraParam, requestPage);
	}

	private Observable prepareExecute(Observable observable) {
		return observable
				.subscribeOn(Schedulers.io())//http请求线程
				.observeOn(Schedulers.io())//AndroidSchedulers.mainThread())//回调所在线程
				.unsubscribeOn(Schedulers.io())//http请求线程
				.retryWhen(new RetryException())//失败后retry
				;
	}

	private Observable resultFilter(Observable observable, final int functionalCode, final Object extraParam, final String requestPage) {
		return observable
//				.onErrorResumeNext(Observable.<String>empty())
//				.map(this)//结果判断
				.map(new Func1<BaseResultEntity<T>, BaseResultEntity>() {
					@Override
					public BaseResultEntity call(BaseResultEntity<T> networkResult) {
						CLog.e("NetworkResult.call", "BaseResultEntity = " + networkResult);
						networkResult.requestCode = functionalCode;
						networkResult.extraParam = extraParam;
						networkResult.requestPage = requestPage;
						if (ResponseCode.CODE_LOGOUT.equals(networkResult.getRetCode())) {
							EventAgent.postSticky(new IEvent.UnLoginEvent(IEvent.CODE_UNLOGIN));
						}
						completed(functionalCode);
						return networkResult;
					}
				});
	}

	public void execute(final Observable observable, Subscriber subscriber, final int functionalCode, final Object extraParam, final String requestPage) {
		if (observable == null || subscriber == null) return;
		if (hadSameExecute(functionalCode)) return;
		executing(functionalCode, subscriber);

//		if (!NetworkUtils.isNetworkAvailable(request.getRxAppCompatActivity())) {//换成静态变量
//			Toast.makeText(request.getRxAppCompatActivity(), R.string.check_network, Toast.LENGTH_SHORT).show();//给presenter决定怎么处理
//			return;
//		}
		observable
				.subscribeOn(Schedulers.io())//http请求线程
				.observeOn(Schedulers.io())//AndroidSchedulers.mainThread())//回调所在线程
				.unsubscribeOn(Schedulers.io())//http请求线程
				.retryWhen(new RetryException())//失败后的retry配置
//				.onErrorResumeNext(Observable.<String>empty())
//				.map(this)//结果判断
				.map(new Func1<BaseResultEntity<T>, BaseResultEntity>() {
					@Override
					public BaseResultEntity call(BaseResultEntity<T> networkResult) {
						CLog.e("NetworkResult.call", "BaseResultEntity = " + networkResult);
						networkResult.requestCode = functionalCode;
						networkResult.extraParam = extraParam;
						networkResult.requestPage = requestPage;
						//ResponseCode must be define value in app module
						if (ResponseCode.CODE_LOGOUT.equals(networkResult.getRetCode())) {
							EventAgent.postSticky(new IEvent.UnLoginEvent(IEvent.CODE_UNLOGIN));
						}
						completed(functionalCode);
						return networkResult;
					}
				})
				.subscribe(subscriber);//数据回调
	}

//	@Override
//	public BaseResultEntity call(BaseResultEntity<T> networkResult) {
//		if ("unlogin".equals(networkResult.getStatus())) {
//			EventAgent.postSticky(new IEvent.UnLoginEvent(IEvent.CODE_LOGOUT));
//		}
//		return networkResult;
//	}

	@SuppressWarnings("unchecked")
	public static <T> T cast(Object obj) {
		return (T) obj;
	}
}
